package com.example.bishe.exception;

import com.example.bishe.util.HttpStatus;
import com.example.bishe.util.RestResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataAccessException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.ServletWebRequest;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * 全局异常捕获
 *
 * @author: LDH
 * @date: 2022年02月06日 21:37
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

//    /**
//     * 用户 token 过期
//     * @return
//     */
//    @ExceptionHandler(value = TokenAuthExpiredException.class)
//    @ResponseBody
//    public Result tokenExpiredExceptionHandler(){
//        log.warn("用户 token 过期");
//        return new Result<>().error("","token 过期",400);
//    }

    /**
     * 功能描述: 参数异常捕获
     * @Param: [e]
     * @Return: com.library.common.Result
     * @Author: LDH
     * @Date: 2022年02月06日 21:37
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseBody
    public RestResult<?> handleValidation(MethodArgumentNotValidException e) {
        BindingResult exceptions = e.getBindingResult();
        if (exceptions.hasErrors()) {
            List<ObjectError> errors = exceptions.getAllErrors();
            if (!errors.isEmpty()) {
                FieldError fieldError = (FieldError) errors.get(0);
                return RestResult.error_msg(e.getClass().getName(), fieldError.getDefaultMessage(),HttpStatus.BAD_REQUEST);
            }
        }
        return RestResult.error_msg("","参数校验异常", HttpStatus.BAD_REQUEST);
    }

    /**
     * 处理空指针的异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value =NullPointerException.class)
    public RestResult<?> exceptionHandler(HttpServletRequest req, NullPointerException e){
        printErr(req,"空指针", e.getMessage());
        return RestResult.error_msg(null,"空指针异常",HttpStatus.ERROR);
    }

    /**
     * 字符串转换为数字格式错误
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value =NumberFormatException.class)
    public RestResult<?> numberHandler(HttpServletRequest req, NumberFormatException e){
        printErr(req,"字符串转换数字", e.getMessage());
        return RestResult.error_msg(e.getClass().getName(),"字符串转换为数字格式错误",HttpStatus.ERROR);
    }

    /**
     * 数组越界
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value =ArrayIndexOutOfBoundsException.class)
    public RestResult<?> arrayHandler(HttpServletRequest req, ArrayIndexOutOfBoundsException e){
        printErr(req,"数组越界", e.getMessage());
        return RestResult.error_msg(e.getClass().getName(),"数组越界",HttpStatus.ERROR);
    }

    /**
     * 类型转换异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value =ClassCastException.class)
    public RestResult<?> classHandler(HttpServletRequest req, ClassCastException e){
        printErr(req,"类型转换异常", e.getMessage());
        return RestResult.error_msg(e.getClass().getName(),"类型转换异常",HttpStatus.ERROR);
    }

    /**
     * 数据库异常
     *
     * @param e   异常
     * @param req 请求
     */
    @ExceptionHandler(value = {DataAccessException.class})
    @ResponseBody
    public RestResult<?> dataAccessException(DataAccessException e, HttpServletRequest req) {
        printErr(req,"数据库异常", e.getMessage());
        // 避免数据库表信息外泄
        return RestResult.error_msg(e.getClass().getName(),"数据库异常",HttpStatus.ERROR);
    }

    /**
     * 处理自定义的业务异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = BizException.class)
    public RestResult<?> bizExceptionHandler(HttpServletRequest req, BizException e){
        printErr(req,"未知", e.getMessage());
        return RestResult.error_msg(null,e.getErrorMsg(),e.getErrorCode());
    }

    /**
     * 处理其他异常
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value =Exception.class)
    public RestResult<?> exceptionHandler(HttpServletRequest req, Exception e){
        printErr(req,"未知", e.getMessage());
        return RestResult.error_msg(e.getClass().getName(),"服务器处理异常",HttpStatus.ERROR);
    }

    /**
     * 异常打印
     */
    public void printErr(HttpServletRequest req,String name,String message){
        log.error("发生[{}]异常:",name);
        log.error("请求路径[{}],请求参数[{}]",req.getRequestURL(),req.getQueryString());
        log.error("异常信息: [{}]",message);
    }
}